package com.hgyc.mom.runner;

import com.hgyc.mom.MomApplication;
import com.hgyc.mom.common.annotation.PrintDataTemplate;
import com.hgyc.mom.common.annotation.PrintFieldProperty;
import com.hgyc.mom.common.constant.CacheConstants;
import com.hgyc.mom.common.print.PrintTemplateDataVO;
import com.hgyc.mom.common.print.PrintTemplateDataField;
import com.hgyc.mom.common.redis.RedisCache;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 启动时，自动扫描加载打印模板数据结构
 * 扫描标有@PrintDataTemplate注解的类
 * @author fwj
 */
@Component
public class PrintTemplateRegister implements ApplicationRunner, ResourceLoaderAware, EnvironmentAware {

    /**
     * 资源加载器
     */
    private ResourceLoader resourceLoader;
    /**
     * 环境
     */
    private Environment environment;

    @Autowired
    private RedisCache redisCache;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 创建scanner
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(resourceLoader);

        // 设置扫描器scanner扫描的过滤条件
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(PrintDataTemplate.class);
        scanner.addIncludeFilter(annotationTypeFilter);

        // 获取指定要扫描的basePackages
        Set<String> basePackages = getBasePackages();

        // 遍历每一个basePackages
        for (String basePackage : basePackages) {
            // 通过scanner获取basePackage下的候选类(有标@Domain)
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            // 遍历每一个候选类，如果符合条件就把他们注册到容器
            List<PrintTemplateDataVO> printTemplateDataVOList = new ArrayList<>();
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    // verify annotated class is an interface
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();

                    // 获取PrintDataTemplate
                    Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(PrintDataTemplate.class.getCanonicalName());

                    PrintTemplateDataVO printTemplateDataVO = new PrintTemplateDataVO();
                    printTemplateDataVO.setName((String) attributes.get("name"));
                    printTemplateDataVO.setValue((String) attributes.get("value"));
                    printTemplateDataVOList.add(printTemplateDataVO);

                    // 数据源字段存入缓存
                    setCacheData(annotationMetadata, attributes);
                }
            }
            redisCache.deleteObject(CacheConstants.PRINT_TEMPLATE_DATA_CACHE_KEY);
            redisCache.setCacheList(CacheConstants.PRINT_TEMPLATE_DATA_CACHE_KEY, printTemplateDataVOList);
        }
    }

    private void setCacheData(AnnotationMetadata annotationMetadata,Map<String, Object> attributes) {
        // 类名（接口全限定名）
        String className = annotationMetadata.getClassName();
        ClassLoader classLoader = PrintTemplateRegister.class.getClassLoader();
        try {
            Class<?> clazz = classLoader.loadClass(className);
            Field[] childFields = clazz.getDeclaredFields();
            //获取父类字段
            Class<?> superclass = clazz.getSuperclass();
            Field[] superclassDeclaredFields = superclass.getDeclaredFields();

            Field[] fields = ArrayUtils.addAll(childFields, superclassDeclaredFields);

            String key = (String) attributes.get("value");

            List<PrintTemplateDataField> templateFieldList = new ArrayList<>();
            for (Field field : fields) {
                PrintTemplateDataField printTemplateDataField = new PrintTemplateDataField();
                printTemplateDataField.setObjectName(key);
                printTemplateDataField.setFieldName(field.getName());

                PrintFieldProperty annotation = field.getAnnotation(PrintFieldProperty.class);
                if (annotation != null) {
                    printTemplateDataField.setDescription(annotation.name());
                }
                printTemplateDataField.setType(field.getType());

                templateFieldList.add(printTemplateDataField);
            }
            redisCache.deleteObject(CacheConstants.PRINT_TEMPLATE_DATA_FIELD_CACHE_KEY + key);
            redisCache.setCacheList(CacheConstants.PRINT_TEMPLATE_DATA_FIELD_CACHE_KEY + key, templateFieldList);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建扫描器
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

    /**
     * 获取base packages
     */
    protected static Set<String> getBasePackages() {
        Set<String> basePackages = new HashSet<>();
        basePackages.add(ClassUtils.getPackageName(MomApplication.class));

        return basePackages;
    }
}
